package org.rupa.core.registry.center;

import org.rupa.common.constant.HeartbeatConstant;
import org.rupa.common.model.HeartbeatBag;
import org.rupa.common.model.HeartbeatInfo;
import org.rupa.common.model.ServiceInfo;

import java.util.concurrent.*;

/**
 * 实现注册中心的心跳机制
 */
public abstract class AbstractRegistryCenterHeartbeatServer implements RegistryCenter {
    /**
     * 讲每次将服务注册到 serviceMap 维护
     */
    protected ConcurrentMap<String, HeartbeatInfo> heartbeatMap = new ConcurrentHashMap<>();
    protected ConcurrentMap<String, ServiceInfo> serviceMap = new ConcurrentHashMap<>();

    /**
     * 启动一个心跳线程去维护一个专门的服务
     * @param serviceInfo
     */
    public void startHeartbeatThread(ServiceInfo serviceInfo) {
//        register(serviceInfo);

        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
        executorService.scheduleWithFixedDelay(
                new HeartbeatDetection(serviceInfo.toString()),
                0,
                30,
                TimeUnit.SECONDS
        );

        HeartbeatInfo heartbeatInfo = HeartbeatInfo
                .builder()
                .lastUpdateTime(0)
                .name(serviceInfo.getName())
                .address(serviceInfo.getAddress())
                .executorService(executorService)
                .build();

        serviceMap.put(serviceInfo.toString(), serviceInfo);
        heartbeatMap.put(serviceInfo.toString(), heartbeatInfo);
    }

    /**
     * 刷新心跳时间
     * @param heartbeatBag
     */
    @Override
    public HeartbeatBag refreshHeartbeat(HeartbeatBag heartbeatBag) {
        heartbeatMap.get(heartbeatBag.getServiceInfo().toString()).setLastUpdateTime(System.currentTimeMillis());

        heartbeatBag.setMode("reply");
        return heartbeatBag;
    }

    /**
     * 连接超时的销毁操作
     * @param name
     */
    public void destroy(String name) {
        heartbeatMap.remove(name).getExecutorService().shutdownNow();
        serviceMap.remove(name);
        heartbeatMap.remove(name);
    }

    private class HeartbeatDetection implements Runnable {
        private String name;

        public HeartbeatDetection(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            HeartbeatInfo heartbeatInfo = heartbeatMap.get(name);
            long lastUpdateTime = heartbeatInfo.getLastUpdateTime();

            if (lastUpdateTime != 0 && System.currentTimeMillis() -  lastUpdateTime > HeartbeatConstant.TIME_OUT) {
                // 连接超时
                unregister(ServiceInfo
                        .builder()
                        .name(name)
                        .address(heartbeatInfo.getAddress())
                        .build());
            }
        }
    }
}
